package org.ofbiz.wvtools.webtools;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;
import java.util.TreeSet;


import org.ofbiz.base.util.Debug;
import org.ofbiz.base.util.UtilMisc;
import org.ofbiz.base.util.UtilProperties;
import org.ofbiz.base.util.UtilValidate;
import org.ofbiz.entity.Delegator;
import org.ofbiz.entity.GenericEntityException;
import org.ofbiz.entity.GenericPK;
import org.ofbiz.entity.GenericValue;
import org.ofbiz.entity.model.ModelEntity;
import org.ofbiz.entity.model.ModelField;
import org.ofbiz.entity.model.ModelFieldType;
import org.ofbiz.entity.model.ModelGroupReader;
import org.ofbiz.entity.model.ModelReader;
import org.ofbiz.entity.model.ModelViewEntity;
import org.ofbiz.entity.util.EntityQuery;
import org.ofbiz.security.Security;
import org.ofbiz.service.DispatchContext;
import org.ofbiz.service.GenericServiceException;
import org.ofbiz.service.LocalDispatcher;
import org.ofbiz.service.ServiceUtil;


import com.google.gson.Gson;

public class WvToolsEntityManage {
	public static final String module = WvToolsEntityManage.class.getName();
    public static final String resource = "WvtoolsUiLabels";
    public static final String err_resource = "WvtoolsUiLabels";
	
	public static Map<String, Object> listWvToolsEntityMaint(DispatchContext ctx,
			Map<String, ? extends Object> context) {
		Map<String, Object> result = ServiceUtil.returnSuccess();

		/**
		 * if (delegator.getDelegatorTenantId() == null) { mgr =
		 * delegator.getModelGroupReader(); entityGroups =
		 * mgr.getGroupNames(delegator.getDelegatorName()).toArray().sort(); }
		 * else { Delegator baseDelegator =
		 * DelegatorFactory.getDelegator(delegator.getDelegatorBaseName());
		 * entityGroups =
		 * EntityUtil.getFieldListFromEntityList(baseDelegator.findList(
		 * "TenantDataSource", EntityCondition.makeCondition("tenantId",
		 * EntityComparisonOperator.EQUALS, delegator.getDelegatorTenantId()),
		 * ['entityGroupName'] as Set, ['entityGroupName'], null, false),
		 * 'entityGroupName', false); }
		 */

		Delegator delegator = ctx.getDelegator();
		Security security = ctx.getSecurity();
		GenericValue userLogin = (GenericValue) context.get("userLogin");
		ModelGroupReader mgr = delegator.getModelGroupReader();
		//Set<String> entityGroups = mgr.getGroupNames(delegator.getDelegatorName());

		try {
			ModelReader reader = delegator.getModelReader();
			TreeSet<String> entities = new TreeSet(reader.getEntityNames());

			List entitiesList = new ArrayList();
			for (String entityName : entities) {
				// entities.each { entityName ->
				ModelEntity entity = reader.getModelEntity(entityName);
				//String entityGroupName = delegator.getEntityGroupName(entity.getEntityName());

				String viewEntity = "N";
				if (entity instanceof ModelViewEntity) {
					viewEntity = "Y";
				}

				String entityPermissionView = "N";
				if (security.hasEntityPermission("ENTITY_DATA", "_VIEW", userLogin)
						|| security.hasEntityPermission(entity.getPlainTableName(), "_VIEW", userLogin)) {
					entityPermissionView = "Y";
				}

				String entityPermissionCreate = "N";
				if (security.hasEntityPermission("ENTITY_DATA", "_CREATE", userLogin)
						|| security.hasEntityPermission(entity.getPlainTableName(), "_CREATE", userLogin)) {
					entityPermissionCreate = "Y";
				}

				Map entityMap = new HashMap();
				entityMap.put("entityName", entity.getEntityName());
				entityMap.put("entityPermissionView", entityPermissionView);
				entityMap.put("entityPermissionCreate", entityPermissionCreate);
				entityMap.put("viewEntity", viewEntity);

				entitiesList.add(entityMap);
			}
			result.put("entitiesList", entitiesList);
			result.put("nfsList", entitiesList);
		} catch (GenericEntityException e) {
			Debug.logError(e.getMessage(), module);
			return ServiceUtil.returnError(e.getMessage());
		}
		return result;
	}
    
    
	public static  Map<String,Object> listWvToolsGeneric(DispatchContext ctx, Map<String, ? extends Object> context){
    	Map<String,Object> result = ServiceUtil.returnSuccess();
    	
    	

    	Delegator delegator = ctx.getDelegator();
    	LocalDispatcher dispatcher = ctx.getDispatcher();
    	Security security = ctx.getSecurity();
		GenericValue userLogin = (GenericValue) context.get("userLogin");
		String entityName = (String) context.get("entityName");
		try {
    	ModelReader reader = delegator.getModelReader();
    	ModelEntity modelEntity = reader.getModelEntity(entityName);


    	result.put("entityName", modelEntity.getEntityName());
    	result.put("plainTableName", modelEntity.getPlainTableName());
    	
    	List fieldList = new ArrayList();
    	Iterator<ModelField> fieldIterator = modelEntity.getFieldsIterator();
    	while (fieldIterator.hasNext()) {
    	    ModelField field = fieldIterator.next();
    	    ModelFieldType type = delegator.getEntityFieldType(modelEntity, field.getType());

    	    Map fieldMap = new HashMap();
    	    fieldMap.put("name", field.getName());
    	    fieldMap.put("isPk", (field.getIsPk() == true) ? "Y" : "N");
    	    fieldMap.put("javaType", type.getJavaType());
    	    fieldMap.put("sqlType", type.getSqlType());
    	    fieldMap.put("param", (context.get(field.getName()) != null ? context.get(field.getName()) : ""));

    	    fieldList.add(fieldMap);
    	}
    	   result.put("fieldList", fieldList);
    	   
    	   
    	   Map inputFields  = new HashMap();
    	   if(UtilValidate.isNotEmpty(context.get("inputFields"))){
    		   inputFields =(Map) context.get("inputFields");
    	   }
    	   inputFields.put("noConditionFind", "Y");
    	   Integer pageNo = 1;
    	   if(UtilValidate.isNotEmpty(context.get("pageNo"))){
    		   pageNo =(Integer) context.get("pageNo");
    	   }
    	   Integer pageSize = 20;
    	   if(UtilValidate.isNotEmpty(context.get("pageSize"))){
    		   pageSize =(Integer) context.get("pageSize");
    	   }
    	   String orderBy = "-createdStamp";
    	   if(UtilValidate.isNotEmpty(context.get("orderBy"))){
    		   orderBy =(String) context.get("orderBy");
    	   }
    	   
    	   
    	   Map serviceContext = new HashMap();
    	  // serviceContext.put("noConditionFind", "Y");
    	   
    	   serviceContext.put("viewSize", pageSize);
    	   serviceContext.put("viewIndex", pageNo-1);
    	   
    	   
    	   
    	   serviceContext.put("orderBy", orderBy);
    	   serviceContext.put("entityName", entityName);
    	   serviceContext.put("inputFields", inputFields);
    	   
    	  
            
           
           
    	   Map serviceResult = dispatcher.runSync("performFindList", serviceContext);
           
    	   result.put("nfsList", serviceResult.get("list"));
           result.put("totalCount", serviceResult.get("listSize"));
           
		} catch (GenericEntityException e) {
			Debug.logError(e.getMessage(), module);
			return ServiceUtil.returnError(e.getMessage());
		} catch (GenericServiceException e) {
			Debug.logError(e.getMessage(), module);
			return ServiceUtil.returnError(e.getMessage());
		}
    	

        
        return result;
    }
    public static  Map<String,Object> getWvToolsGeneric(DispatchContext ctx, Map<String, ? extends Object> context){
    	Map<String,Object> result = ServiceUtil.returnSuccess();
    	
    	
    	Delegator delegator = ctx.getDelegator();
    	LocalDispatcher dispatcher = ctx.getDispatcher();
    	Security security = ctx.getSecurity();
		GenericValue userLogin = (GenericValue) context.get("userLogin");
		
		
		Map inputFields  = new HashMap();
 	   if(UtilValidate.isNotEmpty(context.get("inputFields"))){
 		   inputFields =(Map) context.get("inputFields");
 	   }
 	   
 	   
 	  if(UtilValidate.isEmpty(context.get("inputFields"))&&UtilValidate.isNotEmpty(context.get("inputFieldsJson"))){
 		 String inputFieldsJson =(String) context.get("inputFieldsJson");
 		  Gson gson =new Gson();
 		  inputFields =gson.fromJson(inputFieldsJson, Map.class);
	   }
 	  
 	   
    	String entityName = (String) context.get("entityName");
    	if (UtilValidate.isEmpty(entityName)) {
    		return result;
    	}
    	try {
    	result.put("entityName", entityName);

    	ModelReader reader = delegator.getModelReader();
    	ModelEntity modelEntity = reader.getModelEntity(entityName);

    	//result.put("entity", entity);
    	result.put("plainTableName", modelEntity.getPlainTableName());

    	
    	List fieldList = new ArrayList();
    	Iterator<ModelField> fieldIterator = modelEntity.getFieldsIterator();
    	while (fieldIterator.hasNext()) {
    	    ModelField field = fieldIterator.next();
    	    ModelFieldType type = delegator.getEntityFieldType(modelEntity, field.getType());

    	    Map fieldMap = new HashMap();
    	    fieldMap.put("name", field.getName());
    	    fieldMap.put("isPk", (field.getIsPk() == true) ? "Y" : "N");
    	    fieldMap.put("javaType", type.getJavaType());
    	    fieldMap.put("sqlType", type.getSqlType());
    	    fieldMap.put("param", (context.get(field.getName()) != null ? context.get(field.getName()) : ""));

    	    fieldList.add(fieldMap);
    	}
    	   result.put("fieldList", fieldList);
    	   

    	//String curFindString = "entityName=" + entityName;
    	GenericPK findByPK = delegator.makePK(entityName);
    	Iterator<ModelField> pkIterator = modelEntity.getPksIterator();
    	while (pkIterator.hasNext()) {
    	    ModelField field = pkIterator.next();
    	    ModelFieldType type = delegator.getEntityFieldType(modelEntity, field.getType());
    	    String fval = (String) inputFields.get(field.getName());//TODO   传入map参数数据
    	    if (UtilValidate.isNotEmpty(fval)) {
    	        //curFindString = curFindString + "&" + field.getName() + "=" + fval;
    	        findByPK.setString(field.getName(), fval);
    	    }
    	}
    	result.put("findByPk", findByPK.toString());

    	//curFindString = UtilFormatOut.encodeQuery(curFindString);
    	//result.put("curFindString", curFindString);

    	GenericValue value = null;
    	//only try to find it if this is a valid primary key...
    	if (findByPK.isPrimaryKey()) {
    	    value = delegator.findOne(findByPK.getEntityName(), findByPK, false);
    	}
			
    	    result.put("nfs", value);
			} catch  ( GenericEntityException e) {
				Debug.logError(e.getMessage(), module);
				return ServiceUtil.returnError(e.getMessage());
			}
            return result;
    }
    
    
    
    public static  Map<String,Object> updateGeneric(DispatchContext ctx, Map<String, ? extends Object> context){
    	Map<String,Object> result = ServiceUtil.returnSuccess();
    	
    	
    	Delegator delegator = ctx.getDelegator();
    	LocalDispatcher dispatcher = ctx.getDispatcher();
    	Security security = ctx.getSecurity();
		GenericValue userLogin = (GenericValue) context.get("userLogin");
	
		String entityName = (String) context.get("entityName");
    	
		   Locale locale = (Locale) context.get("locale");
           TimeZone timeZone = (TimeZone) context.get("timeZone");
           Map inputFields  = new HashMap();
     	   if(UtilValidate.isNotEmpty(context.get("inputFields"))){
     		   inputFields =(Map) context.get("inputFields");
     	   }
     	   
     	   
     	  if(UtilValidate.isEmpty(context.get("inputFields"))&&UtilValidate.isNotEmpty(context.get("inputFieldsJson"))){
     		 String inputFieldsJson =(String) context.get("inputFieldsJson");
     		  Gson gson =new Gson();
     		  inputFields =gson.fromJson(inputFieldsJson, Map.class);
    	   }
     	  
     	  
     	  
        if (entityName == null || entityName.length() <= 0) {
            String errMsg = UtilProperties.getMessage(err_resource, "genericWebEvent.entity_name_not_specified", locale) + ".";
            Debug.logWarning("[updateGeneric] The entityName was not specified, but is required.", module);
            return ServiceUtil.returnError(errMsg);
        }


        if (security == null) {
            String errMsg = UtilProperties.getMessage(err_resource,"genericWebEvent.security_object_not_found", locale) + ".";
            Debug.logWarning("[updateGeneric] The security object was not found in the request, please check the control servlet init.", module);
            return ServiceUtil.returnError(errMsg);
        }
        if (delegator == null) {
            String errMsg = UtilProperties.getMessage(err_resource, "genericWebEvent.delegator_object_not_found", locale) + ".";
            Debug.logWarning("[updateGeneric] The delegator object was not found in the request, please check the control servlet init.", module);
            return ServiceUtil.returnError(errMsg);
        }

        ModelReader reader = delegator.getModelReader();
        ModelEntity entity = null;

        try {
            entity = reader.getModelEntity(entityName);
        } catch (GenericEntityException e) {
            Debug.logError(e, module);
        }

        String updateMode = (String) context.get("UPDATE_MODE");

        if (updateMode == null || updateMode.length() <= 0) {
            String errMsg = UtilProperties.getMessage(err_resource, "genericWebEvent.update_mode_not_specified", locale) + ".";
            Debug.logWarning("[updateGeneric] Update Mode was not specified, but is required; entityName: " + entityName, module);
            return ServiceUtil.returnError(errMsg);
        }

        // check permissions before moving on...
        if (!security.hasEntityPermission("ENTITY_DATA", "_" + updateMode, userLogin) &&
            !security.hasEntityPermission(entity.getPlainTableName(), "_" + updateMode, userLogin)) {
                Map<String, String> messageMap = UtilMisc.toMap("updateMode", updateMode, "entityName", entity.getEntityName(), "entityPlainTableName", entity.getPlainTableName());
                String errMsg = UtilProperties.getMessage(err_resource, "genericWebEvent.not_sufficient_permissions_01", messageMap, locale);
                errMsg += UtilProperties.getMessage(err_resource, "genericWebEvent.not_sufficient_permissions_02", messageMap, locale) + ".";

            // not really successful, but error return through ERROR_MESSAGE, so quietly fail
            return ServiceUtil.returnError(errMsg);
        }

        GenericValue findByEntity = delegator.makeValue(entityName);

        // get the primary key parameters...
        String errMsgPk = "";
        Iterator<ModelField> pksIter = entity.getPksIterator();
        while (pksIter.hasNext()) {
            String errMsg = "";
            ModelField field = pksIter.next();

            ModelFieldType type = null;
            try {
                type = delegator.getEntityFieldType(entity, field.getType());
            } catch (GenericEntityException e) {
                Debug.logWarning(e, module);
                Map<String, String> messageMap = UtilMisc.toMap("fieldType", field.getType());
                errMsg += UtilProperties.getMessage(err_resource, "genericWebEvent.fatal_error_param", messageMap, locale) + ".";
            }

            String fval = (String) inputFields.get(field.getName());
            if (UtilValidate.isNotEmpty(fval)) {
                try {
                    findByEntity.setString(field.getName(), fval);
                } catch (Exception e) {
                    Map<String, String> messageMap = UtilMisc.toMap("fval", fval);
                    errMsg = errMsg + "<li>" + field.getColName() + UtilProperties.getMessage(err_resource, "genericWebEvent.conversion_failed", messageMap, locale) + type.getJavaType() + ".";
                    Debug.logWarning("[updateGeneric] " + field.getColName() + " conversion failed: \"" + fval + "\" is not a valid " + type.getJavaType() + "; entityName: " + entityName, module);
                }
            }
        }

        if (errMsgPk.length() > 0) {
            return ServiceUtil.returnError(errMsgPk);
        }

        // if this is a delete, do that before getting all of the non-pk parameters and validating them
        if (updateMode.equals("DELETE")) {
            // Remove associated/dependent entries from other tables here
            // Delete actual main entity last, just in case database is set up to do a cascading delete, caches won't get cleared
            try {
                delegator.removeByPrimaryKey(findByEntity.getPrimaryKey());
            } catch (GenericEntityException e) {
                String errMsg = UtilProperties.getMessage(err_resource, "genericWebEvent.delete_failed", locale) + ": " + e.toString();
                Debug.logWarning(e, errMsg, module);
                return ServiceUtil.returnError(errMsg);
            }

            return result;
        }

        // get the non-primary key parameters
        String errMsgNonPk = "";
        Iterator<ModelField> nopksIter = entity.getNopksIterator();
        while (nopksIter.hasNext()) {
            ModelField field = nopksIter.next();

            ModelFieldType type = null;
            try {
                type = delegator.getEntityFieldType(entity, field.getType());
            } catch (GenericEntityException e) {
                Debug.logWarning(e, module);
                Map<String, String> messageMap = UtilMisc.toMap("fieldType", field.getType());
                errMsgNonPk += UtilProperties.getMessage(err_resource, "genericWebEvent.fatal_error_param", messageMap, locale) + ".";
            }

            String fval = (String) inputFields.get(field.getName());
            if (UtilValidate.isNotEmpty(fval)) {
                try {
                    findByEntity.setString(field.getName(), fval);
                } catch (Exception e) {
                    Map<String, String> messageMap = UtilMisc.toMap("fval", fval);
                    errMsgNonPk += field.getColName() + UtilProperties.getMessage(err_resource,
                            "genericWebEvent.conversion_failed", messageMap, locale) + type.getJavaType() + ".";
                    Debug.logWarning("[updateGeneric] " + field.getColName() + " conversion failed: \"" + fval + "\" is not a valid " + type.getJavaType() + "; entityName: " + entityName, module);
                }
            } else {
                findByEntity.set(field.getName(), null);
            }
        }

        if (errMsgNonPk.length() > 0) {
            return ServiceUtil.returnError(errMsgNonPk);
        }


        // if the updateMode is CREATE, check to see if an entity with the specified primary key already exists
        if (updateMode.equals("CREATE")) {
            GenericValue tempEntity = null;

            try {
                tempEntity = EntityQuery.use(delegator).from(findByEntity.getEntityName()).where(findByEntity.getPrimaryKey()).queryOne();
            } catch (GenericEntityException e) {
                String errMsg = UtilProperties.getMessage(err_resource, "genericWebEvent.create_failed_by_check", locale) + ": " + e.toString();
                Debug.logWarning(e, errMsg, module);

                return ServiceUtil.returnError(errMsg);
            }
            if (tempEntity != null) {
                Map<String, String> messageMap = UtilMisc.toMap("primaryKey", findByEntity.getPrimaryKey().toString());
                String errMsg = "[updateGeneric] " + entity.getEntityName() + UtilProperties.getMessage(err_resource, "genericWebEvent.already_exists_pk", messageMap, locale)+ ".";
                Debug.logWarning(errMsg, module);
            }
        }

        // Validate parameters...
        String errMsgParam = "";
        Iterator<ModelField> fieldIter = entity.getFieldsIterator();
        while (fieldIter.hasNext()) {
            ModelField field = fieldIter.next();

            for (String curValidate : field.getValidators()) {
                Class<?>[] paramTypes = new Class[] {String.class};
                Object[] params = new Object[] {findByEntity.get(field.getName()).toString()};

                String className = "org.ofbiz.base.util.UtilValidate";
                String methodName = curValidate;

                if (curValidate.indexOf('.') > 0) {
                    className = curValidate.substring(0, curValidate.lastIndexOf('.'));
                    methodName = curValidate.substring(curValidate.lastIndexOf('.') + 1);
                }
                Class<?> valClass;

                try {
                    ClassLoader loader = Thread.currentThread().getContextClassLoader();
                    valClass = loader.loadClass(className);
                } catch (ClassNotFoundException cnfe) {
                    Debug.logError("[updateGeneric] Could not find validation class: " + className + "; ignoring.", module);
                    continue;
                }
                Method valMethod;

                try {
                    valMethod = valClass.getMethod(methodName, paramTypes);
                } catch (NoSuchMethodException cnfe) {
                    Debug.logError("[updateGeneric] Could not find validation method: " + methodName + " of class " + className + "; ignoring.", module);
                    continue;
                }

                Boolean resultBool;

                try {
                    resultBool = (Boolean) valMethod.invoke(null, params);
                } catch (Exception e) {
                    Debug.logError("[updateGeneric] Could not access validation method: " + methodName + " of class " + className + "; returning true.", module);
                    resultBool = Boolean.TRUE;
                }

                if (!resultBool.booleanValue()) {
                    Field msgField;
                    String message;

                    try {
                        msgField = valClass.getField(curValidate + "Msg");
                        message = (String) msgField.get(null);
                    } catch (Exception e) {
                        Debug.logError("[updateGeneric] Could not find validation message field: " + curValidate + "Msg of class " + className + "; returning generic validation failure message.", module);
                        message = UtilProperties.getMessage(err_resource, "genericWebEvent.validation_failed", locale) + ".";
                    }
                    errMsgParam += field.getColName() + " " + curValidate + " " + UtilProperties.getMessage(err_resource,
                            "genericWebEvent.failed", locale) + ": " + message;

                    Debug.logWarning("[updateGeneric] " + field.getColName() + " " + curValidate + " failed: " + message, module);
                }
            }
        }

        if (errMsgParam.length() > 0) {
            errMsgParam = UtilProperties.getMessage(err_resource, "genericWebEvent.following_error_occurred", locale) + errMsgParam;
            return ServiceUtil.returnError(errMsgParam);
        }

        if (updateMode.equals("CREATE")) {
            try {
                delegator.create(findByEntity.getEntityName(), findByEntity.getAllFields());
            } catch (GenericEntityException e) {
                Map<String, String> messageMap = UtilMisc.toMap("entityName", entity.getEntityName());
                String errMsg = UtilProperties.getMessage(err_resource, "genericWebEvent.creation_param_failed", messageMap, locale)+ ": " + findByEntity.toString() + ": " + e.toString();
                Debug.logWarning(e, errMsg, module);
                return ServiceUtil.returnError(errMsg);
            }
        } else if (updateMode.equals("UPDATE")) {
            GenericValue value = delegator.makeValue(findByEntity.getEntityName(), findByEntity.getAllFields());

            try {
                value.store();
            } catch (GenericEntityException e) {
                Map<String, String> messageMap = UtilMisc.toMap("entityName", entity.getEntityName());
                String errMsg = UtilProperties.getMessage(err_resource, "genericWebEvent.update_of_param_failed", messageMap, locale)+ ": " + value.toString() + ": " + e.toString();
                Debug.logWarning(e, errMsg, module);
                return ServiceUtil.returnError(errMsg);
            }
        } else {
            Map<String, String> messageMap = UtilMisc.toMap("updateMode", updateMode);
            String errMsg = UtilProperties.getMessage(err_resource, "genericWebEvent.update_of_param_failed", messageMap, locale)+ ".";

            Debug.logWarning("updateGeneric: Update Mode specified (" + updateMode + ") was not valid for entity: " + findByEntity.toString(), module);
            return ServiceUtil.returnError(errMsg);
        }

        return result;
    }
   
    
    
    
}
